15. Scheme

Scheme 是 Lisp 的一种方言,而后者是世界上第二古老的编程语言。Lisp 与 Python 一样,是一个典型的 REPL(Read-Eval-Print Loop,“读取-求值-输入” 循环,又被称为交互式顶层构件,Interactive Toplevel) 语言。在一个典型的 REPL 语言中,仅有三个底层函数,这三个函数通过循环运作可以构建出这种语言所有的内置函数与用户编写的任意代码:

其本身的语法相当简洁优雅,其基本语法只有以下区区几条:

表达式

在 Scheme 中 万物皆表达式。数值等原子表达式是 自求值的,例如 2true 等。其余 组合式(Combinations) 通过小括号括起来。除一些 Scheme 语言规定的特殊形式的组合式外,其余组合式都是组合表达式。

组合表达式本质上只是一个 列表

组合表达式写法上与 Python 不同,看起来是一种 前缀表达式 的写法,标准形式是这样的:(<运算符子表达式> <操作数1> <操作数2> ...)。例如 (+ 1 2)

组合表达式内部可以任意嵌套更多表达式。Scheme 解释器对换行、缩进、多余空格等 Whitespace 不敏感。

特殊格式

Scheme 规定了如下的特殊形式的组合式:

列表

Scheme 只有 列表 一种数据结构,其底部基于 链表,本质上是一个 广义表。Scheme 关于列表有如下的内置方法与属性:

Scheme 还有一些内置的列表处理过程:

引用与符号

本部分所述的内容可能是一个很难理解的概念!

宏(Macros)

在 Scheme 中,与 C 类似,宏在程序源代码被真正执行求值前执行,负责将带有宏的特殊程序代码依据该宏定义的转换规则转换出可以直接运行求值的代码。通过宏,用户可以自行定义大量的特殊格式的代码。

宏的定义方法如下:

(define-macro (<macro-name> <paras>) (<macro-suite>))

宏的执行过程是:解释器对带有宏的表达式求值,当解释器发现宏名时,与常规表达式的求值过程不同,其会在 不对操作数求值 的情况下直接调用定义的宏过程,得到一个新的表达式后再对整个表达式求值。

例如:

(define-macro (twice expr) (list `begin expr expr))

(twice (print 2))

其实际执行会先将带有宏的表达式转换为普通的表达式:

(begin (print 2) (print 2))

然后再执行,输出两个 2

可以预见的是,如果 twice 不是一个宏而是普通函数表达式,则 print 2 会先于函数体运行,只输出一个 2